/*
 * $Id: $
 */
package org.rcgwt.client.ui.grid.controller;

import java.util.ArrayList;
import java.util.List;

import org.rcgwt.client.ui.grid.event.CheckEvent;
import org.rcgwt.client.ui.grid.event.CheckHandler;
import org.rcgwt.client.ui.grid.event.FocusElementEvent;
import org.rcgwt.client.ui.grid.event.FocusElementHandler;
import org.rcgwt.client.ui.grid.event.IIndexesState;
import org.rcgwt.client.ui.grid.event.IModelChangeState;
import org.rcgwt.client.ui.grid.event.ModelElementChangedEvent;
import org.rcgwt.client.ui.grid.event.ModelElementChangedHandler;
import org.rcgwt.client.ui.grid.event.OrderChangedEvent;
import org.rcgwt.client.ui.grid.event.OrderChangedHandler;
import org.rcgwt.client.ui.grid.event.OverElementEvent;
import org.rcgwt.client.ui.grid.event.OverElementHandler;
import org.rcgwt.client.ui.grid.event.PropertyChangedEvent;
import org.rcgwt.client.ui.grid.event.PropertyChangedHandler;
import org.rcgwt.client.ui.grid.internal.GridEventManagerImpl;
import org.rcgwt.client.ui.grid.internal.IntIterator;
import org.rcgwt.client.ui.grid.internal.IntRangeList;
import org.rcgwt.client.ui.grid.internal.model.ICellModel;
import org.rcgwt.client.ui.grid.internal.model.IColumnModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModelDelta;
import org.rcgwt.client.ui.grid.internal.model.IGridEventManager;
import org.rcgwt.client.ui.grid.internal.model.IGridModel;
import org.rcgwt.client.ui.grid.internal.model.IHeaderModel;
import org.rcgwt.client.ui.grid.internal.model.IRowModel;
import org.rcgwt.client.ui.grid.internal.model.IStateMasks;
import org.rcgwt.client.ui.grid.internal.model.ITitleCellModel;
import org.rcgwt.client.ui.grid.internal.model.ITitleRowModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModel.Type;
import org.rcgwt.client.ui.grid.model.IGridWidget;
import org.rcgwt.client.ui.grid.provider.ICheckProvider;
import org.rcgwt.client.ui.grid.provider.IFocusProvider;
import org.rcgwt.client.ui.grid.provider.IGridWidgetProvider;
import org.rcgwt.client.ui.grid.provider.IOrderProvider;
import org.rcgwt.client.ui.grid.provider.IOverProvider;
import org.rcgwt.client.ui.grid.provider.ISelectionProvider;
import org.rcgwt.client.ui.grid.provider.IOrderProvider.IOrderState;
import org.rcgwt.client.ui.grid.renderer.IGridRenderContext;
import org.rcgwt.client.ui.grid.renderer.IGridRenderer;
import org.rcgwt.client.ui.grid.renderer.IViewRenderContext;
import org.rcgwt.client.ui.grid.theme.IGridTheme;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ShowRangeEvent;
import com.google.gwt.event.logical.shared.ShowRangeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;

/**
 * 
 * @author Olivier Oeuillot (latest modification by $Author: $)
 * @version $Revision: $ $Date: $
 */
public class DefaultGridController implements IGridModelController,
		IGridWidgetProvider {

	private HandlerRegistration dataModelHandleRegistration;

	private HandlerRegistration showRangeHandlerRegistration;

	// private IGridWidget gridWidget;

	private HandlerRegistration selectionHandleRegistration;

	private HandlerRegistration overHandleRegistration;

	private IGridEventManager gridEventManager;

	private HandlerRegistration checkHandleRegistration;

	private IElementModelEventController elementModelEventControllers[];

	private HandlerRegistration focusHandleRegistration;

	private HandlerRegistration columnsOrderHandleRegistration;

	private ICaptureEventListener captureEventListener;

	public DefaultGridController() {

	}

	@Override
	public IGridEventManager getGridEventManager(IGridWidget gridWidget) {
		if (gridEventManager == null) {
			gridEventManager = createGridEventManager(gridWidget);

		}
		return gridEventManager;
	}

	protected IGridEventManager createGridEventManager(IGridWidget gridWidget) {
		return new GridEventManagerImpl(gridWidget);
	}

	public void install(final IGridWidget gridWidget) {

		gridWidget.sinkEvents(Event.MOUSEEVENTS | Event.ONSCROLL);

		// Add new handle and keep registration
		dataModelHandleRegistration = gridWidget.getDataModel()
				.addValueChangeHandler(new ValueChangeHandler<IModelChangeState>() {

					@Override
					public void onValueChange(
							ValueChangeEvent<IModelChangeState> event) {
						performGridModelChanged(gridWidget, event);
					}
				});

		showRangeHandlerRegistration = gridWidget
				.addShowRangeHandler(new ShowRangeHandler<Integer>() {

					@Override
					public void onShowRange(ShowRangeEvent<Integer> event) {
						int size = event.getEnd().intValue()
								- event.getStart().intValue() + 1;
						gridWidget
								.updateGrid(event.getStart().intValue(), size);
					}
				});

		gridWidget
				.addModelElementsChangeHandler(new ModelElementChangedHandler() {

					@Override
					public void onModelElementChange(
							ModelElementChangedEvent event) {

						processModelElementChange(gridWidget, event);
					}
				});

		gridWidget.addPropertyChangeHandler(new PropertyChangedHandler() {

			@Override
			public void onPropertyChange(PropertyChangedEvent event) {
				String propertyName = event.getPropertyName();
				if (propertyName.equals("overProvider")) {
					updateOverControl(gridWidget);
					return;
				}
				if (propertyName.equals("selectionProvider")) {
					updateSelectionControl(gridWidget);
					return;
				}
				if (propertyName.equals("checkProvider")) {
					updateCheckControl(gridWidget);
					return;
				}
				if (propertyName.equals("focusProvider")) {
					updateFocusControl(gridWidget);
					return;
				}
				if (propertyName.equals("columnsOrderProvider")) {
					updateColumnsOrderControl(gridWidget);
					return;
				}

			}
		});

		if (gridWidget.getSelectionProvider() != null) {
			updateSelectionControl(gridWidget);
		}
		if (gridWidget.getOverProvider() != null) {
			updateOverControl(gridWidget);
		}
		if (gridWidget.getFocusProvider() != null) {
			updateFocusControl(gridWidget);
		}
		if (gridWidget.getColumnsOrderProvider() != null) {
			updateColumnsOrderControl(gridWidget);
		}
	}

	@Override
	public void installElementEventsListener(
			IViewRenderContext viewRenderContext, IElementModel elementModel,
			Element keysEventsElement, Element scrollEventElement) {

		IGridWidget gridWidget = viewRenderContext.getGridRenderContext()
				.getGridModel().getGridWidget();

		if (keysEventsElement != null) {
			DOM.setEventListener(toElement(keysEventsElement), gridWidget);
			DOM.sinkEvents(toElement(keysEventsElement), Event.KEYEVENTS
					| Event.FOCUSEVENTS);
		}

		if (scrollEventElement != null) {
			DOM.setEventListener(toElement(scrollEventElement), gridWidget);
			DOM.sinkEvents(toElement(scrollEventElement), Event.ONSCROLL);
		}

	}

	private void updateOverControl(final IGridWidget gridWidget) {

		if (overHandleRegistration != null) {
			overHandleRegistration.removeHandler();
			overHandleRegistration = null;
		}

		IOverProvider newOverProvider = gridWidget.getOverProvider();
		if (newOverProvider == null) {
			return;
		}

		overHandleRegistration = newOverProvider
				.addOverElementHandler(new OverElementHandler<IElementModel>() {

					@Override
					public void onOver(OverElementEvent<IElementModel> event) {

						gridEventManager.enter();
						try {
							processOverElement(gridWidget, event
									.getOldElement(), event.getNewElement());

						} finally {
							gridEventManager.exit();
						}
					}
				});
	}

	protected void processOverElement(IGridWidget gridWidget,
			IElementModel oldElement, IElementModel newElementModel) {

		// Log.debug("Change over element old='" + oldElement + "' new='" +
		// newElementModel + "'");

		updateInheritStateMasks(oldElement, newElementModel,
				IStateMasks.OVER_STATE_MASK);
	}

	protected void processColumnsOrderChanged(IGridWidget gridWidget,
			IOrderState oldStates[], IOrderState newStates[], boolean changed[]) {

		if (oldStates != null && oldStates.length > 0) {
			for (IOrderState os : oldStates) {
				int oi = os.getModelIndex();

				boolean found = false;

				for (IOrderState ns : newStates) {
					if (oi != ns.getModelIndex()) {
						continue;
					}

					found = true;
					break;
				}

				if (found) {
					continue;
				}

				updateColumnModelStateMasks(gridWidget.getGridModel(), oi,
						false, IColumnModel.OrderingMark.NONE);
			}
		}

		for (int i = 0; i < changed.length; i++) {
			if (changed[i] == false) {
				continue;
			}

			updateColumnModelStateMasks(
					gridWidget.getGridModel(),
					newStates[i].getModelIndex(),
					true,
					(newStates[i].isAsceding() ? IColumnModel.OrderingMark.ASCENDING
							: IColumnModel.OrderingMark.DESCENDING));
		}
	}

	protected void updateColumnModelStateMasks(IGridModel gridModel,
			int columnModelIndex, boolean set,
			IColumnModel.OrderingMark orderingMask) {

		IColumnModel columnModel = gridModel.listColumnModels()[columnModelIndex];

		columnModel.updateStateMask(~IStateMasks.ORDER_STATE_MASK,
				(set) ? IStateMasks.ORDER_STATE_MASK : 0);

		columnModel.setOrderingMask(orderingMask);

		for (IViewModel viewModel : gridModel.listViewModels()) {
			for (IHeaderModel headerModel : viewModel.listHeaderModels()) {
				for (ITitleRowModel titleRowModel : headerModel
						.listTitleRowModels()) {

					for (ITitleCellModel titleCellModel : titleRowModel
							.listTitleCellModels()) {

						if (titleCellModel.getColumnModel().getModelIndex() != columnModelIndex) {
							continue;
						}

						titleCellModel.updateStateMask(
								~IStateMasks.ORDER_STATE_MASK,
								(set) ? IStateMasks.ORDER_STATE_MASK : 0);
					}
				}
			}
		}
	}

	protected void processFocusElement(IGridWidget gridWidget,
			IElementModel oldElement, IElementModel newElementModel) {

		Log.debug("Change focus element old='" + oldElement + "' new='"
				+ newElementModel + "'");

		updateInheritStateMasks(oldElement, newElementModel,
				IStateMasks.FOCUS_STATE_MASK | IStateMasks.SHOW_STATE_MASK);
	}

	protected void updateInheritStateMasks(IElementModel oldElement,
			IElementModel newElement, int bitMask) {

		List<IElementModel> newList = null;
		List<IElementModel> oldList = null;

		if (oldElement == null) {
			if (newElement == null) {
				return;
			}

			newList = listParents(newElement);

		} else if (newElement == null) {
			oldList = listParents(oldElement);

		} else {
			newList = listParents(newElement);
			oldList = listParents(oldElement);

			List<IElementModel> sharedList = new ArrayList<IElementModel>(
					newList);
			sharedList.retainAll(oldList);

			newList.removeAll(sharedList);
			oldList.removeAll(sharedList);
		}

		if (oldList != null && oldList.isEmpty() == false) {
			for (IElementModel oldModel : oldList) {
				oldModel.updateStateMask(~bitMask, 0);
			}
		}

		if (newList != null && newList.isEmpty() == false) {
			for (IElementModel newModel : newList) {
				newModel.updateStateMask(~bitMask, bitMask);
			}
		}
	}

	private List<IElementModel> listParents(IElementModel elementModel) {
		List<IElementModel> parents = new ArrayList<IElementModel>();

		for (; elementModel != null; elementModel = elementModel.getParent()) {
			parents.add(elementModel);
		}

		return parents;
	}

	protected void processModelElementChange(IGridWidget gridWidget,
			ModelElementChangedEvent event) {

		IElementModelDelta<IGridModel> gridModelDelta = event
				.getGridModelDelta();

		IGridModel gridModel = gridWidget.getGridModel();

		IGridRenderer gridRenderer = gridWidget.getTheme().getGridRenderer(
				gridModel);

		IGridRenderContext gridRenderContext = gridWidget
				.getGridRenderContext();

		Element gridElement = gridWidget.getElement();

		IGridEventManager gridEventManager = getGridEventManager(gridWidget);

		try {
			gridEventManager.enter();

			gridRenderer.processDelta(gridRenderContext, gridElement,
					gridModelDelta);

		} finally {
			gridEventManager.exit();
		}
	}

	@Override
	public void uninstall(IGridWidget gridWidget) {

		if (dataModelHandleRegistration != null) {
			dataModelHandleRegistration.removeHandler();
			dataModelHandleRegistration = null;
		}

		if (showRangeHandlerRegistration != null) {
			showRangeHandlerRegistration.removeHandler();
			showRangeHandlerRegistration = null;
		}
	}

	public void updateSelectionControl(final IGridWidget gridWidget) {

		if (selectionHandleRegistration != null) {
			selectionHandleRegistration.removeHandler();

			selectionHandleRegistration = null;
		}

		if (gridWidget.isSelectable() == false) {
			return;
		}

		ISelectionProvider selectionProvider = gridWidget
				.getSelectionProvider();
		if (selectionProvider == null) {
			return;
		}

		selectionHandleRegistration = selectionProvider
				.addSelectionHandler(new SelectionHandler<IIndexesState>() {

					@Override
					public void onSelection(SelectionEvent<IIndexesState> event) {
						gridEventManager.enter();
						try {
							processIndexesStateEvent(gridWidget, event
									.getSelectedItem(),
									IStateMasks.SELECTED_STATE_MASK);

						} finally {
							gridEventManager.exit();
						}
					}
				});
	}

	public void updateCheckControl(final IGridWidget gridWidget) {

		if (checkHandleRegistration != null) {
			checkHandleRegistration.removeHandler();

			checkHandleRegistration = null;
		}

		if (gridWidget.isSelectable() == false) {
			return;
		}

		ICheckProvider checkProvider = gridWidget.getCheckProvider();
		if (checkProvider == null) {
			return;
		}

		checkHandleRegistration = checkProvider
				.addCheckHandler(new CheckHandler<IIndexesState>() {

					@Override
					public void onCheck(CheckEvent<IIndexesState> event) {
						gridEventManager.enter();
						try {
							processIndexesStateEvent(gridWidget, event
									.getCheckedItem(),
									IStateMasks.CHECKED_STATE_MASK);

						} finally {
							gridEventManager.exit();
						}
					}
				});
	}

	@Override
	public void onBrowserEvent(IGridWidget gridWidget, Event event) {

		IGridModel gridModel = gridWidget.getGridModel();

		Element element = DOM.eventGetTarget(event);

		IElementModel elementModel = gridModel.findElementModel(element);

		int eventType = DOM.eventGetType(event);

		if (false) {
			Log.debug("Browser event model=" + elementModel + " type="
					+ eventType + " event=" + event + " element=" + element);
		}

		if (elementModel == null) {
			return;
		}

		IGridEventManager eventManager = gridWidget.getGridModelController()
				.getGridEventManager(gridWidget);

		eventManager.enter();

		try {

			if (captureEventListener != null
					&& captureEventListener.onBrowserEvent(this, gridWidget,
							elementModel, event)) {
				return;
			}

			switch (eventType) {
			case Event.ONMOUSEOVER:
				onElementModelOver(gridWidget, elementModel, event);
				return;

			case Event.ONMOUSEOUT:
				onElementModelOut(gridWidget, elementModel, event);
				return;

			case Event.ONSCROLL:
				onGridModelScroll(gridModel, elementModel, event);
				return;

			case Event.ONMOUSEMOVE:
				// onElementModelScroll(gridModel, elementModel, event);

				return;

			case Event.ONLOSECAPTURE:

			case Event.ONFOCUS:
				onElementModelFocus(gridWidget, elementModel, event);
				return;

			case Event.ONBLUR:
				onElementModelBlur(gridWidget, elementModel, event);
				return;

			case Event.ONKEYPRESS:
				onElementModelKeyPress(gridWidget, elementModel, event);

				return;
			}

			switch (elementModel.getType()) {
			case CELL:
				onCellModelEvent(gridWidget, (ICellModel) elementModel,
						eventType, event);
				break;

			case ROW:
				onRowModelEvent(gridWidget, (IRowModel) elementModel,
						eventType, event);
				break;

			case TITLE_CELL:
				onTitleCellModelEvent(gridWidget,
						(ITitleCellModel) elementModel, eventType, event);
				break;

			default:
				break;
			}
		} finally {
			eventManager.exit();
		}
	}

	protected void onTitleCellModelEvent(IGridWidget gridWidget,
			ITitleCellModel cellModel, int eventType, Event event) {

		onCellRowModelEvent(gridWidget, cellModel, eventType, event);
	}

	protected void onCellModelEvent(IGridWidget gridWidget,
			ICellModel cellModel, int eventType, Event event) {

		onCellRowModelEvent(gridWidget, cellModel, eventType, event);
	}

	protected void onRowModelEvent(IGridWidget gridWidget, IRowModel rowModel,
			int eventType, Event event) {

		onCellRowModelEvent(gridWidget, rowModel, eventType, event);
	}

	protected void onCellRowModelEvent(IGridWidget gridWidget,
			IElementModel elementModel, int eventType, Event event) {

		switch (eventType) {
		case Event.ONMOUSEDOWN:
			IFocusProvider focusProvider = gridWidget.getFocusProvider();
			if (focusProvider != null && focusProvider.hasFocus() == false) {
				ensureFocus(gridWidget, elementModel, event);
			}

			onElementModelMouseDown(gridWidget, elementModel, event);

			event.stopPropagation();
			event.preventDefault();
			return;
		}
	}

	protected void ensureFocus(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		IFocusProvider focusProvider = gridWidget.getFocusProvider();

		IViewModel focusViewModel = getViewModel(gridWidget, event);

		gridWidget.setFocus(focusViewModel, focusViewModel);

		focusProvider.getFocus(); // On simule tout de suite !

	}

	protected void onElementModelMouseDown(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		IElementModelEventController elementModelEventControllers[] = getElementModelEventControllers(gridWidget);

		for (IElementModelEventController elementModelEventController : elementModelEventControllers) {
			if (elementModelEventController.processSelection(this, gridWidget,
					elementModel, event)) {
				break;
			}
		}
	}

	protected IElementModelEventController[] getElementModelEventControllers(
			IGridWidget gridWidget) {

		if (elementModelEventControllers != null) {
			return elementModelEventControllers;
		}

		elementModelEventControllers = createElementModelEventControllers(gridWidget);

		return elementModelEventControllers;
	}

	private IElementModelEventController[] createElementModelEventControllers(
			IGridWidget gridWidget) {

		List<IElementModelEventController> l = new ArrayList<IElementModelEventController>();

		fillElementModelEventControllersList(gridWidget, l);

		IElementModelEventController cts[] = l
				.toArray(new IElementModelEventController[l.size()]);
		return cts;
	}

	protected void fillElementModelEventControllersList(IGridWidget gridWidget,
			List<IElementModelEventController> l) {

		IGridTheme theme = gridWidget.getTheme();

		theme.addElementEventControllers(l, gridWidget);
	}

	protected void onElementModelFocus(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		Log.debug("OnElementModelFocus=" + elementModel);

		IElementModelEventController elementModelEventControllers[] = getElementModelEventControllers(gridWidget);

		next_element: for (; elementModel != null; elementModel = elementModel
				.getParent()) {

			for (IElementModelEventController elementModelEventController : elementModelEventControllers) {
				if (elementModelEventController.processFocus(this, gridWidget,
						elementModel, event)) {
					break next_element;
				}
			}
		}
	}

	protected void onElementModelBlur(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		Log.debug("OnElementModelBlur=" + elementModel);

		IElementModelEventController elementModelEventControllers[] = getElementModelEventControllers(gridWidget);

		next_element: for (; elementModel != null; elementModel = elementModel
				.getParent()) {

			for (IElementModelEventController elementModelEventController : elementModelEventControllers) {
				if (elementModelEventController.processBlur(this, gridWidget,
						elementModel, event)) {
					break next_element;
				}
			}
		}
	}

	protected void onElementModelOver(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		IElementModelEventController elementModelEventControllers[] = getElementModelEventControllers(gridWidget);

		for (IElementModelEventController elementModelEventController : elementModelEventControllers) {
			if (elementModelEventController.processOver(this, gridWidget,
					elementModel, event)) {
				break;
			}
		}
	}

	protected void onElementModelOut(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		IElementModelEventController elementModelEventControllers[] = getElementModelEventControllers(gridWidget);

		for (IElementModelEventController elementModelEventController : elementModelEventControllers) {
			if (elementModelEventController.processOut(this, gridWidget,
					elementModel, event)) {
				break;
			}
		}
	}

	private void updateFocusControl(final IGridWidget gridWidget) {

		if (focusHandleRegistration != null) {
			focusHandleRegistration.removeHandler();
			focusHandleRegistration = null;
		}

		IFocusProvider newFocusProvider = gridWidget.getFocusProvider();
		if (newFocusProvider == null) {
			return;
		}

		focusHandleRegistration = newFocusProvider
				.addFocusElementHandler(new FocusElementHandler<IElementModel>() {

					@Override
					public void onFocus(FocusElementEvent<IElementModel> event) {

						gridEventManager.enter();
						try {
							processFocusElement(gridWidget, event
									.getOldElementModel(), event
									.getNewElementModel());

						} finally {
							gridEventManager.exit();
						}
					}
				});
	}

	private void updateColumnsOrderControl(final IGridWidget gridWidget) {

		if (columnsOrderHandleRegistration != null) {
			columnsOrderHandleRegistration.removeHandler();
			columnsOrderHandleRegistration = null;
		}

		IOrderProvider newColumnsOrderProvider = gridWidget
				.getColumnsOrderProvider();
		if (newColumnsOrderProvider == null) {
			return;
		}

		columnsOrderHandleRegistration = newColumnsOrderProvider
				.addOrderChangedHandler(new OrderChangedHandler<IOrderProvider.IOrderState[]>() {

					@Override
					public void onOrderChanged(
							OrderChangedEvent<IOrderProvider.IOrderState[]> event) {

						gridEventManager.enter();
						try {
							processColumnsOrderChanged(gridWidget, event
									.getOldOrderState(), event
									.getNewOrderState(), event.getChangedMask());

						} finally {
							gridEventManager.exit();
						}
					}
				});
	}

	protected void onElementModelKeyPress(IGridWidget gridWidget,
			IElementModel elementModel, Event event) {

		IElementModelEventController elementModelEventControllers[] = getElementModelEventControllers(gridWidget);

		for (IElementModelEventController elementModelEventController : elementModelEventControllers) {
			if (elementModelEventController.processKeyPress(this, gridWidget,
					elementModel, event)) {
				break;
			}
		}
	}

	protected void performGridModelChanged(IGridWidget gridWidget,
			ValueChangeEvent<IModelChangeState> event) {

		IGridModel gridModel = gridWidget.getGridModel();

		IModelChangeState modelChangeState = event.getValue();

		// int rowStart = modelChangeState.getStart();

		switch (modelChangeState.getType()) {
		case UPDATE:
			Log.debug("GridEvent receive an UPDATE event");

			// updateRow(gridModel, rowStart, modelChangeState.getCount());
			break;

		case STRUCTURE:
			Log.debug("GridEvent receive a STRUCTURE event");

			if (gridModel.getGridWidget().isGridSorted()) {
				// updateAllGrid(gridModel);
				break;
			}

			int diff = modelChangeState.getDeltaCount();

			if (diff < 0) {
				// removeRow(gridModel, rowStart, -diff);

			} else if (diff > 0) {
				gridWidget.updateGrid(modelChangeState.getStart(), diff);
				// insertRow(gridModel, modelChangeState.getStart(), diff);
			}

			int count = modelChangeState.getCount();
			if (count > 0) {
				// updateRow(gridModel, rowStart, count);
			}

			break;
		}
	}

	protected void processIndexesStateEvent(IGridWidget gridWidget,
			IIndexesState state, int bitmask) {

		// Log.debug("State=" + state.toString());

		IGridModel gridModel = gridWidget.getGridModel();

		IGridRenderContext gridRenderContext = gridWidget
				.getGridRenderContext();

		// Unselected all
		IntRangeList allVisibleRowModelIndexes = gridRenderContext
				.listAllVisibleRowModelIndexes();

		IntRangeList unselectedRows = (IntRangeList) state.getRemovedRows();
		if (unselectedRows.isEmpty() == false) {
			unselectedRows = unselectedRows
					.intersects(allVisibleRowModelIndexes);
		}

		IntRangeList selectedRows = (IntRangeList) state.getAddedRows();
		selectedRows = selectedRows.intersects(allVisibleRowModelIndexes);

		for (IntIterator it = unselectedRows.iterator(); it.hasNext();) {
			int rowModelIndex = it.next();

			IRowModel row = gridModel.searchRowModel(rowModelIndex);
			if (row == null) {
				continue;
			}

			row.updateStateMask(~bitmask, 0);
		}

		// Selected
		for (IntIterator it = selectedRows.iterator(); it.hasNext();) {
			int rowModelIndex = it.next();

			IRowModel row = gridModel.searchRowModel(rowModelIndex);
			if (row == null) {
				continue;
			}

			row.updateStateMask(~bitmask, bitmask);
		}
	}

	/*
	 * 
	 * class ResizeListener { private boolean dragging = false;
	 * 
	 * private int startx;
	 * 
	 * private int startWidth;
	 * 
	 * protected Element thElement;
	 * 
	 * protected IColumn column;
	 * 
	 * public void reset() { thElement = null; column = null; dragging = false;
	 * }
	 * 
	 * // private int column;
	 * 
	 * public void onBrowserEvent(Event event, Element th, IColumn column) {
	 * 
	 * if (column == null) return;
	 * 
	 * switch (DOM.eventGetType(event)) { case Event.ONMOUSEDOWN: this.thElement
	 * = th; this.column = column; onMouseDown(event); break; case
	 * Event.ONMOUSEMOVE: if (!dragging) { this.thElement = th; }
	 * onMouseMove(event); break; case Event.ONMOUSEUP: onMouseUp(event); break;
	 * case Event.ONLOSECAPTURE: onLoseCapture(event); break; } }
	 * 
	 * private void onLoseCapture(Event event) { Window.alert("Lose capture");
	 * thElement = null; }
	 * 
	 * private void onMouseDown(Event event) { startx = event.getClientX();
	 * startWidth = thElement.getOffsetWidth(); dragging = true; //
	 * DOM.setCapture( thElement); }
	 * 
	 * private void onMouseMove(Event event) { if (thElement == null) return;
	 * int clientx = event.getClientX(); if (dragging) { int delta = clientx -
	 * startx; resizeColumn(delta); } else { int absLeft =
	 * thElement.getAbsoluteLeft() - Window.getScrollLeft(); int absRight =
	 * absLeft + thElement.getOffsetWidth(); if (clientx >= absRight -
	 * RESIZE_WIDTH && clientx < absRight) {
	 * thElement.getStyle().setProperty("cursor", "e-resize"); } else {
	 * thElement.getStyle().setProperty("cursor", ""); } } }
	 * 
	 * private void onMouseUp(Event event) { dragging = false;
	 * 
	 * // DOM.releaseCapture(thElement); }
	 * 
	 * private void resizeColumn(int deltaWidth) { int width = startWidth +
	 * deltaWidth; if (width < 0) { width = 0; }
	 * 
	 * // Resize header TD if (column.isValidWidth(width)) {
	 * column.setWidth(width); // thElement.setAttribute("width", "" + width +
	 * "px");
	 * 
	 * // synchroniseHeadtoBody(); } else { dragging = false; } } }
	 * 
	 * private final ResizeListener resizeColumn = new ResizeListener();
	 * 
	 * private void onClientMouseUpEvent(IGridRenderContext gridRenderContext,
	 * Event event, Element element) { Element e = DOM.eventGetTarget(event);
	 * 
	 * / * if (tableHead != null) { if (tableHead.isOrHasChild(e)) {
	 * 
	 * resizeColumn.onBrowserEvent(event, e, getColumn(e)); return; }
	 * resizeColumn.reset(); } /
	 * 
	 * }
	 * 
	 * private void onClientMouseMoveEvent(IGridRenderContext gridRenderContext,
	 * Event event, Element element) {
	 * 
	 * int viewModelIndex = gridRenderContext.getViewModelIndex(element); if
	 * (viewModelIndex >= 0) { IViewModel view = views[viewModelIndex];
	 * 
	 * IViewRenderContext viewRenderContext = gridRenderContext
	 * .getViewRenderContext(view);
	 * 
	 * view.onClientMouseMoveEvent(viewRenderContext, event, element); } }
	 * 
	 * protected void onClientMouseOverEvent(IGridRenderContext
	 * gridRenderContext, Event event, Element element) {
	 * 
	 * int viewModelIndex = gridRenderContext.getViewModelIndex(element); if
	 * (viewModelIndex >= 0) { IViewModel view = views[viewModelIndex];
	 * 
	 * IViewRenderContext viewRenderContext = gridRenderContext
	 * .getViewRenderContext(view);
	 * 
	 * view.onClientMouseOverEvent(viewRenderContext, event, element); } }
	 * 
	 * protected void onClientMouseOutEvent(IGridRenderContext
	 * gridRenderContext, Event event, Element element) {
	 * 
	 * int viewModelIndex = gridRenderContext.getViewModelIndex(element); if
	 * (viewModelIndex >= 0) { IViewModel view = views[viewModelIndex];
	 * 
	 * IViewRenderContext viewRenderContext = gridRenderContext
	 * .getViewRenderContext(view);
	 * 
	 * view.onClientMouseOutEvent(viewRenderContext, event, element); } }
	 * 
	 * private void onClientMouseDownEvent(IGridRenderContext gridRenderContext,
	 * Event event, Element element) {
	 * 
	 * // Quel type d'element int id = -1;
	 * 
	 * / * Element e = DOM.eventGetTarget(event); // Check si c'est le header if
	 * ((tableHead != null) && (tableBody != null)) {
	 * 
	 * if (tableHead.isOrHasChild(e)) {// Nous sommes dans le header if
	 * (tableHead.getRows().getItem(0).isOrHasChild(e)) {
	 * resizeColumn.onBrowserEvent(event, e, getColumn(e));
	 * 
	 * return; } } else { resizeColumn.reset(); }
	 * 
	 * if (tableBody.isOrHasChild(e)) {// Nous sommes dans le body
	 * 
	 * id = gridRenderContext.getRowModelIndexFromElement(e); if (id > -1) {
	 * onRowElementMouseDownEvent(event, id); DOM.eventPreventDefault(event); }
	 * } } /
	 * 
	 * }
	 */
	private void onGridModelScroll(IGridModel gridModel,
			IElementModel elementModel, Event event) {

		for (; elementModel != null && elementModel.getType() != Type.VIEW;) {
			elementModel = elementModel.getParent();
		}

		if (elementModel == null) {
			return;
		}

		IViewModel viewModel = (IViewModel) elementModel;

		IViewController viewModelController = gridModel.getGridWidget()
				.getTheme().getViewController(viewModel);
		if (viewModelController == null) {
			return;
		}

		Element viewElement = viewModel.getViewModelElements().getViewElement();

		viewModelController.onScrollEvent(viewModel, viewElement, event);
	}

	public static IViewModel getViewModel(IGridWidget gridWidget, Event event) {

		Element element = DOM.eventGetTarget(event);

		IViewModel viewModel = gridWidget.getGridModel().findViewModel(element);

		return viewModel;
	}

	protected static com.google.gwt.user.client.Element toElement(
			Element element) {
		return (com.google.gwt.user.client.Element) element;
	}

	public void setCaptureEventListener(
			ICaptureEventListener captureEventListener) {
		if (this.captureEventListener != null) {
			throw new IllegalStateException("Several capture listener !");
		}

		this.captureEventListener = captureEventListener;
	}

	public void releaseCapture(ICaptureEventListener captureEventListener) {
		if (this.captureEventListener != captureEventListener) {
			throw new IllegalStateException("Different capture listener !");
		}

		this.captureEventListener = null;

	}

	public static ITitleCellModel getTitleCellModel(IElementModel elementModel) {
		for (; elementModel != null; elementModel = elementModel.getParent()) {
			if (elementModel.getType() != Type.TITLE_CELL) {
				continue;
			}

			return (ITitleCellModel) elementModel;
		}

		return null;
	}

	public static ITitleRowModel getTitleRowModel(IElementModel elementModel) {
		for (; elementModel != null; elementModel = elementModel.getParent()) {
			if (elementModel.getType() != Type.TITLE_ROW) {
				continue;
			}

			return (ITitleRowModel) elementModel;
		}

		return null;
	}

	public static IRowModel getRowModel(IElementModel elementModel) {
		for (; elementModel != null; elementModel = elementModel.getParent()) {
			if (elementModel.getType() != Type.ROW) {
				continue;
			}

			return (IRowModel) elementModel;
		}

		return null;
	}
}
